﻿/*
 * 2011年5月26，效果好了很多。。。
 */

package com.example.android.BluetoothChat;

import java.io.BufferedOutputStream;


import java.util.concurrent.Semaphore;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


import android.R.array;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager.WakeLock;
import android.provider.MediaStore.Images;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
//import android.graphics.ImageFormat;//这是android 2.2支持的！！！

/**
 * This is the main Activity that displays the current chat session.
 */
public class BluetoothChat extends Activity {
    // Debugging
    private static final String TAG = "BluetoothChat";
    private static final boolean D = true;
    int debugsum = 0;

    private static final boolean use_Mac = true;
    private static final boolean isTaken = false;
    // Message types sent from the BluetoothChatService Handler
    public static final int MESSAGE_STATE_CHANGE = 1;
    public static final int MESSAGE_READ = 2;
    public static final int MESSAGE_WRITE = 3;
    public static final int MESSAGE_DEVICE_NAME = 4;
    public static final int MESSAGE_TOAST = 5;

    // Key names received from the BluetoothChatService Handler
    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";
    
    //yuv数据数组
    //byte[] sendbuffer = new byte[1024*1024*3];
    //byte[] sendbuffer = new byte[115200];
    byte[] sendbuffer = new byte[460800]; //640*480*1.5 = 460800B,即是最大的preview的YUV420SP数据的大小
    byte[] tempsendbuffer = new byte[460800];
    
    //互斥访问yuv数组信号量
    private Semaphore yuvbufferlock = new Semaphore(1);
    //互斥访问jpeg数组信号量
    public static Semaphore jpegbufferlock = new Semaphore(1);
        
    
    byte[] psendbuffer =null;
    int datesendlength = 0;
    DecodingJpegThread sendthread = null;
    int previewwidth = 0;
    int previewheight = 0;
    
    //生成jpeg函数类
	public YuvImage yuvImage = null;
	public Rect rectangle = null;			   	    
    public int frame = 0;
    public int sendlength = 0;
    public int times = 0;
    
    //生成的jpeg所在的内存数组流
    //public  ByteArrayOutputStream arrayout = new ByteArrayOutputStream( );  
	//public int jpeglength = 0;  
    
    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE = 1;
    private static final int REQUEST_ENABLE_BT = 2;

    // Layout Views
    private TextView mTitle;
    private ListView mConversationView; //显示通信信息的控件

    //机器人行为控制按钮定义
    private Button mButton1;
    private Button mButton2;
    private Button mButton3;
    private Button mButton4;
    private Button mButton5;
    private Button mButton6;
    private Button mButton7;
    private Button mButton8;
    private Button mButtonStart;
    
    //按钮的时间监听对象
    MyButtonListener mButtonListener;
    
    private boolean isStart =false;
    
    //显示预览和处理预览的控件，相机设备对象
	private SurfaceView mSurfaceView;
	private SurfaceHolder mSfHolder;
	private Camera mCamera = null;
	Bitmap mBitmap = null;
    
	//注意回调对象PictureCallback的作用，在拍照时被调用，用于拍照后读取Camera中的图像数据，然后保存
	private Camera.PictureCallback  pictureCallback=null ;
	private Camera.PreviewCallback  previewCallback=null; 
    
    // Name of the connected device
    private String mConnectedDeviceName = null;
    // Array adapter for the conversation thread
    private ArrayAdapter<String> mConversationArrayAdapter;
    // String buffer for outgoing messages
    private StringBuffer mOutStringBuffer;
    // Local Bluetooth adapter
    private BluetoothAdapter mBluetoothAdapter = null;
    // Member object for the chat services
    private BluetoothChatService mChatService = null;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(D) Log.e(TAG, "+++ ON CREATE +++");
        
        Log.i("cyy","onCreat....");

        // Set up the window layout
        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        setContentView(R.layout.main);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);    
        
    	File file = new File("/sdcard/RobotController");
    	RandomAccessFile debugfile ;
        if (!file.exists())
			try {
				file.createNewFile();
			    debugfile = new RandomAccessFile(file, "rw");
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
        
        
         // Set up the custom title
         mTitle = (TextView) findViewById(R.id.title_left_text);
         mTitle.setText(R.string.app_name);
         mTitle = (TextView) findViewById(R.id.title_right_text);

        //机器人行为控制按钮。。。设置长按的事件监听
       mButton1 = (Button)findViewById(R.id.button1);
       mButton2 = (Button)findViewById(R.id.button2);
       mButton3 = (Button)findViewById(R.id.button3);
       mButton4 = (Button)findViewById(R.id.button4);
       mButton5 = (Button)findViewById(R.id.button5);
       mButton6 = (Button)findViewById(R.id.button6);
       mButton7 = (Button)findViewById(R.id.button7);
       mButton8 = (Button)findViewById(R.id.button8);
       mButtonStart = (Button)findViewById(R.id.buttonStart);
       
       mButtonListener = new MyButtonListener();
       
       mButton1.setOnLongClickListener(mButtonListener);
       mButton2.setOnLongClickListener(mButtonListener);
       mButton3.setOnLongClickListener(mButtonListener);
       mButton4.setOnLongClickListener(mButtonListener);
       mButton5.setOnLongClickListener(mButtonListener);
       mButton6.setOnLongClickListener(mButtonListener);
       mButton7.setOnLongClickListener(mButtonListener);
       mButton8.setOnLongClickListener(mButtonListener);
       mButtonStart.setOnLongClickListener(mButtonListener);
               
        // Get local Bluetooth adapter
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // If the adapter is null, then Bluetooth is not supported
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
           
            finish();
            return;
        }
        
        
        //创建用于相机预览的回调对象
        pictureCallback = new Camera.PictureCallback() {
    		public void onPictureTaken(byte[] data, Camera camera) {
    			Log.i("cyy","onPictureTaken");
    			Toast.makeText(getApplicationContext(), "正在保存照片……datalength is"+data.length, Toast.LENGTH_LONG).show();
    			mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    			File file = new File("/sdcard/"+ new DateFormat().format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg");
    			try {
    				file.createNewFile();
    				Log.i("cyy","create file successed");
    				BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
    				mBitmap.compress(Bitmap.CompressFormat.PNG, 80, os);
    				
    				os.flush();
    				os.close();
    				Toast.makeText(getApplicationContext(), "图片保存完毕，在存储卡的根目录", Toast.LENGTH_LONG).show();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}	
    		}
    	};
    	
    	
    	//已经成功验证，该函数可以被正确调用，当前任务是增加网络模块！！！
    	//将date[]中数据赋值给另外一个数据，让另一个线程去发送！
    	//验证测试表明，发送UDP数据包的大小有限制，一次发送1KB！！！所以要测试UDP数据包的大小，否则丢失非常严重！！！
    	previewCallback = new Camera.PreviewCallback() {
			private int tick =0;
			private int numframe=0;
			boolean first = true;
			@Override
			public synchronized void onPreviewFrame(byte[] data, Camera camera) {
				//将data[]中的数据发送出去，data[]的数据是线程安全的，有同步机制
			    try {
			    	psendbuffer = data;
			    	datesendlength = data.length;
			    	//System.arraycopy(sendbuffer , 0 , data , 0 , data.length);
			    	
			    	//规定，各个线程互斥得访问sendbuffer
			    	yuvbufferlock.acquire();
			    	System.arraycopy(data , 0 , sendbuffer , 0 , data.length);	
			    	yuvbufferlock.release();
			    	
			    	sendthread.start();		
			    	/*改进计划，需要给sendbuffer上锁，否则发送的数据可能是乱的*/
			    	
			    	
			    	//终于发现了问题，，貌似是这个复制数组出现了错误，复制的是无效的空数据？？？？
			    	//原来是我把目的数据和源数据弄反了，复制数据全是0
		
			     	//Toast.makeText(getApplicationContext(), "onPreView datalenth is "+data.length , Toast.LENGTH_LONG).show(); 

			    	//截取一帧YUV数据存储在本地，用来验证YUV420SP转RGB24或RGB32的算法
			        /*
			    	File file = new File("/sdcard/pal.yuv");
			        if (!file.exists())
			         file.createNewFile();
			         RandomAccessFile raf = new RandomAccessFile(file, "rw");
			         raf.write(data);
			         raf.close();
			         Toast.makeText(getApplicationContext(), "视频截取成功", Toast.LENGTH_LONG).show();
			        */
			    	
			       } catch (Exception ex) {
			       Log.v("System.out", ex.toString());
			       }//endtry

			}//endonPriview
		};
 	
        //设置预览控件
        mSurfaceView = (SurfaceView)this.findViewById(R.id.SurfaceView01); 
        mSfHolder = mSurfaceView.getHolder();
        
        mSfHolder.addCallback(new SurfaceHolder.Callback() {
			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
				Log.i("camer","SurfaceHolder.Callback....surfaceDestroyed");
				//Toast.makeText(getApplicationContext(), "surfaceDestroyed", Toast.LENGTH_LONG).show();
				mCamera.stopPreview();
				mCamera.release();
				mCamera = null;
			}
			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				//当预览视图创建的时候开启相机
				mCamera = Camera.open();
				try {
					Log.i("camer","SurfaceHolder.Callback....surfaceCreated");
					//Toast.makeText(getApplicationContext(), "surfaceCreated", Toast.LENGTH_LONG).show();
					//mCamera.setDisplayOrientation();
					//设置预览
					mCamera.setPreviewDisplay(holder);
					 sendthread = new DecodingJpegThread();
					//sendthread.start();//改到onPreveiw去!
				} catch (IOException e) {
					// 释放相机资源并置空
					mCamera.release();
					mCamera = null;
				}
			}
			
			//当surface视图数据发生变化时，处理预览信息
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
				//相机的参数是否设置有效，可以查看在DDMS中查看Log.i得知！！！
				Log.i("camer","SurfaceHolder.Callback....surfaceChanged");
			//	Toast.makeText(getApplicationContext(), "surfaceChanged", Toast.LENGTH_LONG).show();
				Camera.Parameters parameters = mCamera.getParameters();
				parameters.setPictureFormat(PixelFormat.JPEG);
				
				//获取caera支持的PictrueSize，看看能否设置？？
				List<Size> pictureSizes = mCamera.getParameters().getSupportedPictureSizes();
				List<Size> previewSizes = mCamera.getParameters().getSupportedPreviewSizes();
				List<Integer> previewFormats = mCamera.getParameters().getSupportedPreviewFormats();
				List<Integer> previewFrameRates = mCamera.getParameters().getSupportedPreviewFrameRates();
				Log.i("camer","cyy support parameters is ");
					
				Size psize = null;
				for(int i=0 ; i<pictureSizes.size() ; i++)
				{
				   psize = pictureSizes.get(i);
				   Log.i("camer","cyy PictrueSize,width: "+psize.width+" height"+psize.height);
				}
				for(int i=0 ; i<previewSizes.size() ; i++)
				{
				   psize = previewSizes.get(i);
				   Log.i("camer","cyy PreviewSize,width: "+psize.width+" height"+psize.height);
				}
				Integer pf = null;
				for(int i=0 ; i<previewFormats.size() ; i++)
				{
					pf = previewFormats.get(i);
					Log.i("camer","cyy previewformates:"+pf);
				}
				
				/*  //导致异常，不知道为什么。。
				for(int i=0 ; i<previewFrameRates.size() ; i++)
				{
					  pf = previewFrameRates .get(0);
					  Log.i("camer","cyy previewFrameRates:"+pf);
				}*/
				
			
				
				//终于修改成功，根据Log.i()打印的信息，得知系统支持的各种参数，从而再设置！
				parameters.setPictureSize(640, 480);

     			parameters.setPreviewSize(320 , 240);  //设置成功
				//parameters.setPreviewSize(176 , 144); 

				//parameters.setPreviewFrameRate(15);    //没有修改成功。
	            parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);  
                 
	            
	     	  // parameters.setRotation(90);////在portrait模式下，预览方向始终不变化?
	            //这个在播放的时候似乎变形了，变矮了？？
	            //mCamera.setDisplayOrientation(90);
				mCamera.setPreviewCallback(previewCallback);
				mCamera.setParameters(parameters);	
				mCamera.startPreview();
				
				Camera.Size csize = mCamera.getParameters().getPreviewSize ();
				previewheight = csize.height;
				previewwidth = csize.width;
				
				Log.i("cyy", "cyy ,after setting, previewSize:width: "+csize.width+" height: "+csize.height);
				csize = mCamera.getParameters().getPictureSize();
				Log.i("cyy", "cyy ,after setting, pictruesize:width: "+csize.width+" height: "+csize.height);
			    Log.i("cyy", "cyy ,after setting, previewformate is "+mCamera.getParameters().getPreviewFormat());
			    Log.i("cyy", "cyy ,after setting, previewframetate is "+mCamera.getParameters().getPreviewFrameRate());
			    
			    //终于设置成功了！！！
			}
		});//endofaddcallback
         
        mSfHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        
    
    }//endOncreat
    
    
	//按下相机键的处理函数，关键是拍照
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		Log.i("cyy","MainActivity.onKeyDown");
		if(keyCode == KeyEvent.KEYCODE_CAMERA)
		{
			if(mCamera != null)
			{
				Log.i("cyy","mCamera.takePicture");
				//当按下相机按钮时，执行相机对象的takePicture()方法,该方法有三个回调对象做入参，不需要的时候可以设null
				//将图像数据从Camera对象读取到回调对象pictureCallack中
				mCamera.takePicture(null, null, pictureCallback);
				//能否设定定时器1秒内调用takePicture15次？也就是单独使用一个线程，每次tackPictrue之后休眠40毫秒？
				//效率如何？延迟大否？数据量应该会很小，而且压缩转换的效率肯定比我自己写的要高！！！
				return mSurfaceView.onKeyDown(keyCode, event);
			}
		
		}  	
    	//按下键盘上返回按钮
    	if(keyCode == KeyEvent.KEYCODE_BACK){
    		ExitOptionsDialog();
    		return true;
    	}else{		
    		return super.onKeyDown(keyCode, event);
    	}
    	
		
	}
    
    @Override
    public void onStart() {
        super.onStart();
        if(D) Log.e(TAG, "++ ON START ++");

        // If BT is not on, request that it be enabled.
        // setupChat() will then be called during onActivityResult
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        // Otherwise, setup the chat session
        } else {
            if (mChatService == null) setupChat();
        }
    }

    @Override
    public synchronized void onResume() {
        super.onResume();
        if(D) Log.e(TAG, "+ ON RESUME +");

        // Performing this check in onResume() covers the case in which BT was
        // not enabled during onStart(), so we were paused to enable it...
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
        if (mChatService != null) {
            // Only if the state is STATE_NONE, do we know that we haven't started already
            if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
              // Start the Bluetooth chat services
              mChatService.start();
            }
        }
    }
    
    private class MyButtonListener implements OnLongClickListener{
		@Override
		public boolean onLongClick(View v) {
			//TODO Auto-generated method stub
			//mTextMainState.setText("long click on button___");
			if(mChatService.getState() == BluetoothChatService.STATE_CONNECTED)
	      {
			String message = null;
			switch( v.getId() )
			{
				case R.id.button1:
					message = "1";
				break;
				case R.id.button2:
					message = "2";
				break;
				case R.id.button3:
					message = "3";
				break;
				case R.id.button4:
					message = "4";
				break;
				case R.id.button5:
					message = "5";
				break;
				case R.id.button6:
					message = "6";
				break;				
				case R.id.button7:
					message = "7";
				break;
				case R.id.button8:
					message = "8";
					break;	
				case R.id.buttonStart:
				{
					   if(isStart)
					   {
						  isStart = false;
						  message = "stop";
						  mButtonStart.setText("START");
					   }else
					   {
						  isStart = true;
						  message = "start";
						  mButtonStart.setText("STOP");
					   }
				    break;
				}
					}
			 if(isStart)
			 {
				 sendMessage(message);
			 }	
	      }//endif
			
			return false;
		}
    	
    }
    
    private void setupChat() {
        Log.d(TAG, "setupChat()");

        //显示蓝牙通信内容的控件
        // Initialize the array adapter for the conversation thread
        mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
        mConversationView = (ListView) findViewById(R.id.Mesgview);
        mConversationView.setAdapter(mConversationArrayAdapter);
        
        // Initialize the BluetoothChatService to perform bluetooth connections
        mChatService = new BluetoothChatService(this, mHandler);

        // Initialize the buffer for outgoing messages
        mOutStringBuffer = new StringBuffer("");
    }

    @Override
    public synchronized void onPause() {
        super.onPause();
        if(D) Log.e(TAG, "- ON PAUSE -");
    }

    @Override
    public void onStop() {
        super.onStop();
        if(D) Log.e(TAG, "-- ON STOP --");
        
        Toast.makeText(this, "senddate number is "+debugsum, Toast.LENGTH_LONG).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Stop the Bluetooth chat services
        if (mChatService != null) mChatService.stop();
        if(D) Log.e(TAG, "--- ON DESTROY ---");
    }

    private void ensureDiscoverable() {
        if(D) Log.d(TAG, "ensure discoverable");
        if (mBluetoothAdapter.getScanMode() !=
            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            startActivity(discoverableIntent);
        }
    }

    /**
     * Sends a message.
     * @param message  A string of text to send.
     */
    private void sendMessage(String message) {
        // Check that we're actually connected before trying anything
        if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
            Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        // Check that there's actually something to send
        if (message.length() > 0) {
            // Get the message bytes and tell the BluetoothChatService to write
            byte[] send = message.getBytes();
            mChatService.write(send);

            // Reset out string buffer to zero 
            mOutStringBuffer.setLength(0);
        }
    }


    // The Handler that gets information back from the BluetoothChatService
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MESSAGE_STATE_CHANGE:
                if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
                switch (msg.arg1) {
                case BluetoothChatService.STATE_CONNECTED:
                    mTitle.setText(R.string.title_connected_to);
                    mTitle.append(mConnectedDeviceName);
                    mConversationArrayAdapter.clear();
                    break;
                case BluetoothChatService.STATE_CONNECTING:
                    mTitle.setText(R.string.title_connecting);
                    break;
                case BluetoothChatService.STATE_LISTEN:
                case BluetoothChatService.STATE_NONE:
                    mTitle.setText(R.string.title_not_connected);
                    break;
                }
                break;
            case MESSAGE_WRITE:
                byte[] writeBuf = (byte[]) msg.obj;
                // construct a string from the buffer
                String writeMessage = new String(writeBuf);
                mConversationArrayAdapter.add("Me:  " + writeMessage);
                break;
            case MESSAGE_READ:
                byte[] readBuf = (byte[]) msg.obj;
                // construct a string from the valid bytes in the buffer
                String readMessage = new String(readBuf, 0, msg.arg1);
                mConversationArrayAdapter.add(mConnectedDeviceName+":  " + readMessage);
                break;
            case MESSAGE_DEVICE_NAME:
                // save the connected device's name
                mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
                Toast.makeText(getApplicationContext(), "Connected to "
                               + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_TOAST:
                Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
                               Toast.LENGTH_SHORT).show();
                break;
            }
        }
    };

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(D) Log.d(TAG, "onActivityResult " + resultCode);
        switch (requestCode) {
        case REQUEST_CONNECT_DEVICE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                // Get the device MAC address
                String address = data.getExtras()
                                     .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
                // Get the BLuetoothDevice object
                BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
                // Attempt to connect to the device
                mChatService.connect(device);
            }
            break;
        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // Bluetooth is now enabled, so set up a chat session
                setupChat();
            } else {
                // User did not enable Bluetooth or an error occured
                Log.d(TAG, "BT not enabled");
                Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }
  //退出软件的时候确认选择      	
    private void ExitOptionsDialog()
    {
    	  AlertDialog.Builder builder = new AlertDialog.Builder(this); 
    	  builder.setMessage("是否退出程序") 
    	         .setCancelable(false) 
    	         .setPositiveButton("确定", new DialogInterface.OnClickListener() { 
    	             public void onClick(DialogInterface dialog, int id) { 
    	            	 android.os.Process.killProcess(android.os.Process.myPid());
    	             } 
    	         }) 
    	         .setNegativeButton("取消", new DialogInterface.OnClickListener() { 
    	             public void onClick(DialogInterface dialog, int id) { 
    	                  dialog.cancel(); 
    	             } 
    	         }); 
    	  AlertDialog alert = builder.create();
    	  alert.show();
    }

    
//创建menu按键菜单
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.option_menu, menu);
        return true;
    }
    
//menu按键菜单的选择函数
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.scan:
            // Launch the DeviceListActivity to see devices and do scan
            Intent serverIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
            return true;
        case R.id.discoverable:
            // Ensure this device is discoverable by others
        	Toast.makeText(this, "senddate number is "+debugsum, Toast.LENGTH_LONG).show();
           // ensureDiscoverable();
            return true;
        }
        return false;
    }
    
  //能否添加一个队列，生成的Jpeg帧放在队列里面，队列满了，则自动删除多余，或者httpthread发送出去。
  //同时保证DecondingJpegThread（只有一个线程）和多个httpthread（多个这样的线程）互斥访问。
  //这也是一个非常经典的生产者消费者模型，一个生产者，多个消费者
  //这样过于复杂，由于生产者线程是随机产生的，
    //改进方案二、能否在监听后产生的新线程里面生成jpeg然后在传输去.
    
    
    class DecodingJpegThread extends Thread
    {
 	   public void run()
 	   {
 		   try {
 		       
 			   //Log.i("cyy","cyy DecodingJpegThread thread....");
 			   		   
 			   //设置设置转换成Jpeg先关函数
 			   rectangle = new Rect(0 , 0 , previewwidth , previewheight);	
 			   yuvImage = new YuvImage(tempsendbuffer, PixelFormat.YCbCr_420_SP , previewwidth, previewheight, null);
 			   

 			   int i=1, PORT=8080;
 			   ServerSocket server=null;
 			   Socket client=null;
 			   
 			   //创建服务器socket
				server=new ServerSocket(PORT);
 				Log.i("cyy" , "Web Server is listening on port "+server.getLocalPort()+"IP:"+server.getInetAddress().getHostAddress()); 
 			    
 		       
 			   while(true)
 			   {
 				 
				   client=server.accept();
		      	  // new HttpServer(client,i ,(int)jpeglength).start();          
				   new HttpServer(client,i).start();   //终于找到了错误，传给http信息头中的jpeglength是上一次的长度
                   // sleep(10);                                           	   
 			   }
 			   
 			   
 	         } catch (Exception e) 
 	         {
 	             e.printStackTrace();
 	        }//endtry
 	         	         
 		    }//endrun
 		   
    }//endclssD
    
    
    //互斥调用该函数，发送jpeg图片线程互斥访问这个，
    //返回Jpeg帧的长度
 
   public   synchronized int decodetojpeg(ByteArrayOutputStream arrayout) throws Exception
    { 
	   
	     int jpegframelen = 0;
	     
	     //获取Yuv数据。	   
		   yuvbufferlock.acquire();
		   System.arraycopy(sendbuffer, 0, tempsendbuffer, 0, datesendlength);
		   yuvbufferlock.release();
						   
		   if( 0 != arrayout.size())     //每次循环,arrayout只保存当前最新的一帧图片！	
		   {
			   arrayout.reset();         
		   }
		      
		  
		   //将yuv数据编码成jpeg
        if(yuvImage.compressToJpeg(rectangle, 80, arrayout))
		   {
			   Log.i("cyy" , "cyy....compress jpeg successed to arrayoutstream,lenth:"+arrayout.toByteArray().length);
			   jpegframelen = arrayout.toByteArray().length;
			   frame++;
			   
			   //在这个里面，生成的jpeg没有任何问题。
			   /*
			    String tempname = frame+"deco.jpg";
				FileOutputStream fileout = new FileOutputStream("/sdcard/"+ tempname);  	   					 
				fileout.write(arrayout.toByteArray(), 0, jpegframelen);
				fileout.close();
				*/
			   
		   }else
		   {
			   Log.i("cyy" , "cyy....failed to compress jpeg to arrayoutstream");
			   return 0;
		   }
        return jpegframelen;

    }
    
   public  class  HttpServer  extends Thread 
   {
   	  Socket client; // 连接Web浏览器的socket字
         int counter; // 计数器

         ByteArrayOutputStream byteoutputstream;   
         int mjpeglength;
         String sendjpegname;
         private byte[] httpsendbuffer = new byte[1024*30];  //30KB的发送缓冲区，存放一次完整的jpeg流响应
         private byte[] sendfilebuffer = new byte[1024*10];
         long begin = 0;
         long end = 0;
         
            String stdheader = "Connection: close\r\n"
					         +"Server: MJPG-Streamer/0.2\r\n" 
					         +"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"
					         +"Pragma: no-cache\r\n"
					         +"Expires: Mon, 3 Jan 2000 12:34:56 GMT\r\n";
         
            String boundary = "boundarydonotcross";
      //   static int sendframes = 0;
         
         public  HttpServer(Socket cs , int num)
         {  
	       	  Log.i("cyy","new thread:"+num);
	       	  client = cs;
	       	  counter = num;
	       	  byteoutputstream = new ByteArrayOutputStream();
	       	  //mjpeglength = jpglen;
	       	  begin = System.currentTimeMillis();
         }
         
         public void run() // 线程体
        {
   		try 
   		{
   			
   			String destIP=client.getInetAddress().toString(); // 客户机IP地址
   			int destport=client.getPort(); // 客户机端口号
   			Log.i("cyy","cyy...Connection "+counter+":connected to "+destIP+" on port "+destport+".");
   			PrintStream outstream=new PrintStream(client.getOutputStream());
   			//DataOutputStream outstream=new DataOutputStream(client.getOutputStream());
   			DataInputStream instream=new DataInputStream(client.getInputStream());
   			String inline=instream.readLine(); // 读取Web浏览器提交的请求信息
   			Log.i("cyy","cyy...Received:"+inline);
   			if (getrequest(inline))
   			{ // 如果是GET请求
   					String filename=getfilename(inline);
   									
   					String jpegname = filename.substring(filename.indexOf('.')+1);
   						
   					//如果是获取请求Jpeg帧，则直接发送Jpge流过去。
   					if(jpegname.equals("jpg"))
   					{
   					 //方案二，一次传输多帧jpeg，两次响应						
   					 //1、先发送信息头
   						
   					   String jheader = "HTTP/1.0 200 OK\r\n"
   	                  +stdheader	                  
   	                  +"Content-Type: multipart/x-mixed-replace;boundary="+boundary+"\r\n"
   	                  +"\r\n"
   	                  +"--"+boundary+"\r\n";
   					   
   					  outstream.write(jheader.getBytes(), 0 , jheader.getBytes().length);
   					  outstream.flush();
   						//2、再发送jpeg流
   					    while(true)
   					     {
		   						sendjpegname = frame+".jpg"; 
		   						
		   						//jpeg帧输送到线程私有的byteoutputstream里面，这样不会造成数据冲突
		   						mjpeglength = decodetojpeg(byteoutputstream);
		   						if(mjpeglength == 0)
		   						{
		   							Log.i("cyy" , "error ,jpenglength =0!!!");
		   							//jpeg生成错误，senderro()给client
		   						}
		   						
	
		   						String httpheader 
		   						= "Content-Type: image/jpeg\r\n"
		   	                    + "Content_Length: " + mjpeglength +"\r\n"
		   	                    + "\r\n";
		   						
		   						outstream.write(httpheader.getBytes() , 
		   								        0 , httpheader.getBytes().length);
		   						outstream.flush();
		   						
		   						outstream.write(byteoutputstream.toByteArray() ,
		   								        0 , mjpeglength);
		   						outstream.flush();
		   						
		   						String strbunde = "\r\n--" +boundary +"\r\n";
		   						outstream.write(strbunde.getBytes() ,
		   								        0 , strbunde.length() );
		   						outstream.flush();
	   						
   					     }//endwhile  						
   					}else//请求的是其他文件，则在webserver上面寻找该文件，如果找到了，则发送过去。
   					{
   						   Log.i("cyy","cyy...file :"+filename+" ,beging to search");	
   						   
   							File file=new File("/sdcard/"+filename);
   							
   							if (file.exists()) 
   							{ 
   		   					    int filelen=(int)file.length();
   	   							DataInputStream fileins = new DataInputStream(new FileInputStream(file));
   	   							byte[] readfilebuf = new byte[filelen];
   	   							fileins.readFully(readfilebuf, 0 , filelen);
   		   					    String httpheader 
   		   					              = "HTTP/1.0 200 OK\r\n"
   		   					              +stdheader
                                          +"Content_Type:text/html\r\n"
                                          +"Content_Length:"+filelen+"\r\n"
                                          +"\r\n";
                                System.arraycopy(httpheader.getBytes() , 0,
                                		         httpsendbuffer ,   0  , httpheader.getBytes().length); 
                                System.arraycopy(readfilebuf,            0 ,
                                		         httpsendbuffer , httpheader.getBytes().length , filelen);
                                
   		   					    outstream.write(httpsendbuffer, 0 , 
   		   					    	httpheader.getBytes().length+filelen);
   		   					    outstream.flush();
   								
   					        }else 
   							{ // 文件不存在时
   					        	   Log.i("cyy","cyy...clien's requeset file:"+file.getName()+"not exits!");
   									String notfound="<html><head><title>Not Found</title></head><body><h1>Error 404-file not found</h1></body></html>";							
   									outstream.println("HTTP/1.0 404 no found");
   									outstream.println("Content_Type:text/html");
   									outstream.println("Content_Length:"+notfound.length()+2);
   									outstream.println("");
   									outstream.println(notfound);
   									outstream.flush();   			
   									
   							}
   					}
   																		
   			}
 
   	          end = System.currentTimeMillis();	          
   	          Log.i("cyy","thread consumed time is "+( end-begin));
   	         
   	           sleep(100);
   	           client.close();
   	           
   	          long end2 = System.currentTimeMillis();	  
   	          Log.i("cyy","thread delay for socket time is "+( end2-end));
   	          
   	      }catch (Exception e)
   	      {
   			// TODO: handle exception
   		  } //endtry
   	}//endrun
         
       	//获取请求类型是否为“GET” 
        	boolean getrequest(String s)
        	{ 
        		if(s.length()>0)
        		{
        		   if(s.substring(0,3).equalsIgnoreCase("GET"))
        			   return true;
        		}
        		return false;
        	}

        	String getfilename(String s) 
        	{
        				String f=s.substring(s.indexOf(' ')+1);
        				f=f.substring(0,f.indexOf(' '));
        				try 
        				{
        				   if(f.charAt(0)=='/')
        				   f=f.substring(1);
        				}catch(StringIndexOutOfBoundsException e)
        				{
        				   Log.i("cyy","Exception:"+e);
        				}
        				if(f.equals("")) 
        					f="index.html";
        				 return f;
        	}

        				//把指定文件发送给Web浏览器 
        	void sendfile(PrintStream outs,File file)
        	{
        	    try{
        				DataInputStream in=new DataInputStream(new FileInputStream(file));
        				int len=(int)file.length();
        				byte buf[]=new byte[len];
        				in.readFully(buf);
        				outs.write(buf,0,len);
        				outs.flush();
        				in.close();
        	       }catch (Exception e)
        	        {
        	    	   Log.i("cyy"," sendfile exception");
        			  e.printStackTrace();
        		    }
        	}//endsendfile     
    }
   
}
